package com.example.ws.handler.elog;

import static io.javalin.apibuilder.ApiBuilder.prefixPath;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.RandomAccess;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.input.ReversedLinesFileReader;

import com.example.ws.GlobalConfLoader;
import com.example.ws.util.Tuple3;

import ch.qos.logback.core.joran.conditional.ElseAction;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class ELogService {

    public static final ELogService instance = new ELogService();
    private ELogService() {}
    public static ELogService getInstance() { return instance; }

    private final String LOG_URL = GlobalConfLoader.getConfprop().getProperty(GlobalConfLoader.CONFIG_KEY_REMOTE_LOG_PATH);
    // private final String LOG_URL = "http://192.168.9.7:8080/screenlog?platform=release&zone_id=1";

    private final String DEF_NULL_LOG = "NULL";

    private final Pattern pattern = Pattern.compile(".*##\\[([A-Z_]+)\\]\\[(\\d+/\\d+/\\d+) (\\d+:\\d+:\\d+)\\]\\[(\\w+):(\\d+)\\](</span>)?(.*)");

    public List<ELogEntity> log(String cookie) {
        String weblogs = catchLog(cookie);
        return parse(weblogs);
    }

    // 抓取日志
    private String catchLog(String cookie) {
        
        OkHttpClient client = new OkHttpClient();
        HttpUrl.Builder uHttpUrlBuilder = HttpUrl.parse(LOG_URL).newBuilder();
        // uHttpUrlBuilder.addQueryParameter("name", "cahx_dev_1");
        Request request = new Request.Builder()
                                    .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0")
                                    .header("Cookie", cookie)
                                    .url(uHttpUrlBuilder.toString())
                                    .get()
                                    .build();
        try {
            return client.newCall(request).execute().body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return DEF_NULL_LOG;
    }

    private ELogEntity parseSingle(String line) {
        ELogEntity eLogEntity = new ELogEntity();
        Matcher matcher = pattern.matcher(line);
            while (matcher.find()) {
                String typeStr = matcher.group(1);
                String dataStr = matcher.group(2);
                String timeStr = matcher.group(3);
                String modStr = matcher.group(4);
                String lineStr = matcher.group(5);
                String infoStr = matcher.group(7);
                eLogEntity.setTypeStr(typeStr);
                eLogEntity.setDateStr(dataStr);
                eLogEntity.setTimeStr(timeStr);
                eLogEntity.setModStr(modStr);
                eLogEntity.setLineStr(lineStr);
                Tuple3<Boolean,String,String> roleResult = ELogUtils.extractRole(infoStr);
                eLogEntity.setHasRole(roleResult.v1);
                eLogEntity.setInfoStr(roleResult.v2);
                eLogEntity.setRoleStr(roleResult.v3);
            }
        return eLogEntity;
    }

    private List<ELogEntity> parse(String webConsoleLog) {
        // 按行切分
        String[] lines = webConsoleLog.split("<br/>");
        // lines:
        // <span class="g">##[INFO][date time][mod:line]</span>info_txt
        // ##[DEBUG][datetime][mod:line]info_txt
        // <span class="r">##[ERROR][date time][mod:line]</span>info_txt
        // <span class="g">##[INFO][2024/4/20 21:50:5][rank_zone:448]</span>排行榜[138]收到更新,长度为[0]
        List<ELogEntity> list = new ArrayList<>();
        int count = 0;
        for (String line : lines) {
            ELogEntity single = parseSingle(line);
            single.setSeqId(count);
            count++;
            list.add(single);
        }
        return list;
    }


    private final String localLogAbsAddr = GlobalConfLoader.getConfprop().getProperty(GlobalConfLoader.CONFIG_KEY_SERVER_LOCAL_PATH);
    // private final String localLogAbsAddr = "D:/git/workspace/cahx_wspace/future/zone/cahx_xlllocal_2/screenlog.0";
    private volatile RandomAccessFile reader = null;
    private volatile long localFileReadPos = 0;
    private static final Object LOCAL_LOG_LOCK = new Object();
    
    // 获取从linePos开始的所有最新日志
    public List<ELogEntity> logLocal(int linePos) {
        if (reader == null) {
            synchronized (LOCAL_LOG_LOCK) {
                if (reader == null) {
                    catchLocalLogInit();
                }
            }
        }
        try {
            if (localFileReadPos != reader.length()) {
                synchronized (LOCAL_LOG_LOCK) {
                    if (localFileReadPos != reader.length()) {
                        parseToEnd(localFileReadPos);
                        localFileReadPos = reader.length();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return LocalELogCache.getInstance().fromToEnd(linePos);
    }
    
    // 初始化本地日志
    private synchronized void catchLocalLogInit() {
        // (cahx_xlllocal_2@127.0.0.1)5> camo^H ^H^H ^H^H ^H^H ^H^G^G^G^G^Gcamp_real_redbag_http:i()^H^H^[[C^[[C.^M
        // ^[[1m^[[31m##[ERROR][2024/4/25 0:27:7][camp_real_redbag_http:321]^[[m123^M
        // ##[DEBUG][2024/4/25 0:27:7][camp_real_redbag_http:322]666^M
        // ^[[1m^[[33m##[XLL_DEBUG][2024/4/25 0:27:7][camp_real_redbag_http:323]^[[m1231^M
        // ^[[0m^[[32m##[INFO][2024/4/25 0:27:7][camp_real_redbag_http:324]^[[m1231^M
        // ok^M
        // (cahx_xlllocal_2@127.0.0.1)6> ^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H(cahx_xlllcal_2@127.0.0.1)6> camp_real_redbag_http:i().^M
        // ^[[1m^[[31m##[ERROR][2024/4/25 0:27:10][camp_real_redbag_http:321]^[[m123^M
        // ##[DEBUG][2024/4/25 0:27:10][camp_real_redbag_http:322]666^M
        // ^[[1m^[[33m##[XLL_DEBUG][2024/4/25 0:27:10][camp_real_redbag_http:323]^[[m1231^M
        // ^[[0m^[[32m##[INFO][2024/4/25 0:27:10][camp_real_redbag_http:324]^[[m1231^M
        // ok^M
        // (cahx_xlllocal_2@127.0.0.1)7>
        try {
            File file = new File(localLogAbsAddr);
            System.out.println("|" + file.getAbsolutePath() + "|" + file.exists() + "|" + localLogAbsAddr + "|");
            reader = new RandomAccessFile(file, "r");
            System.out.println("catchLocalLogInit: " + reader.length());
            localFileReadPos = reader.length() * 98 / 100;
            localFileReadPos = initPos(localFileReadPos, reader);
            parseToEnd(localFileReadPos);
            localFileReadPos = reader.length();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void parseToEnd(long startPos) {
        String line = "";
        List<ELogEntity> list = new LinkedList<>();
        try {
            reader.seek(startPos);
            int count = 0;
            while (line != null) {
                line = new String(line.getBytes("ISO-8859-1"), "utf-8");
                ELogEntity singleLocalELog = parseSingleLocalELog(line);
                singleLocalELog.setSeqId(count);
                count++;
                line = reader.readLine();
                System.out.print("\r| " + 1.0 * reader.getFilePointer() / reader.length() + "%" + "            |");
                if (singleLocalELog.getTypeStr().equals("null")) {
                    continue;
                }
                list.add(singleLocalELog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        LocalELogCache.getInstance().addAll(list);
    }

    // (颜色)(打印类型:ERROR|...)(日期)(时间)(模块)(行数)(颜色标识闭环)(信息)(结尾)
    private static final Pattern localElogPattern = Pattern.compile("(\\^\\[\\[\\d+m\\^\\[\\[\\d+m)?##\\[(\\w+)\\]\\[(\\d+/\\d+/\\d+) (\\d+:\\d+:\\d+)\\]\\[?(\\w+)?:(\\d+)?\\]?(\u001b\\[m)?(.*)(\\^M)*");

    // 解析单条本地日志
    private ELogEntity parseSingleLocalELog(String line) {
        Matcher matcher = localElogPattern.matcher(line);
        ELogEntity eLogEntity = new ELogEntity();
        while (matcher.find()) {
            String typeStr = matcher.group(2);
            String dataStr = matcher.group(3);
            String timeStr = matcher.group(4);
            String modStr  = matcher.group(5);
            String lineStr = matcher.group(6);
            String infoStr = matcher.group(8);
            eLogEntity.setTypeStr(typeStr);
            eLogEntity.setDateStr(dataStr);
            eLogEntity.setTimeStr(timeStr);
            eLogEntity.setModStr(modStr);
            eLogEntity.setLineStr(lineStr);
            Tuple3<Boolean,String,String> infoTuple = ELogUtils.extractRole(infoStr);
            eLogEntity.setHasRole(infoTuple.v1);
            eLogEntity.setInfoStr(infoTuple.v2);
            eLogEntity.setRoleStr(infoTuple.v3);
            return eLogEntity;
        }
        return eLogEntity;
    }

    // 初始化pos，寻找到beginPos的所在行的下一行开始
    public long initPos(long beginPos, RandomAccessFile randomAccessFile) throws IOException {
        randomAccessFile.seek(beginPos);
        byte c = randomAccessFile.readByte();
        while (c != '\r' && c != '\n') {
            c = randomAccessFile.readByte();
        }
        randomAccessFile.readLine();
        return randomAccessFile.getFilePointer();
    }



    public static void main(String[] args) throws Exception {
        testp2();
    }

    public static void testp2() {
        String []tstr = {
            "##[DEBUG][2024/3/28 17:34:40][lib_proto:234]C-->S [Code:10900 Acc:xll21 Desc: Data:{p_10900_c2s,10900,3}]",
            "^[[0m^[[32m##[INFO][2024/4/26 14:54:30][camp_real_redbag_http:324]^[[m1231^M",
            "^[[1m^[[31m##[ERROR][2024/4/26 14:54:30][camp_real_redbag_http:321]^[[m123^M",
            "##[DEBUG][2024/4/26 14:54:30][camp_real_redbag_http:322]666^M",
            "^[[1m^[[33m##[XLL_DEBUG][2024/4/26 14:54:30][camp_real_redbag_http:323]^[[m1231^M",
            "^[[0m^[[32m##[INFO][2024/4/26 14:54:30][camp_real_redbag_http:324]^[[m1231^M"
        };
        ELogService eLogService = ELogService.getInstance();
        for (String str : tstr) {
            ELogEntity eLogEntity = eLogService.parseSingleLocalELog(str);
            System.out.println(eLogEntity);
        }
        
    }

    public static void testlocal() throws Exception {
        ELogService eLogService = ELogService.getInstance();
        RandomAccessFile randomAccessFile = new RandomAccessFile("D:/git/workspace/cahx_wspace/future/zone/cahx_xlllocal_2/screenlog.0", "r");
        long pos = randomAccessFile.length() * 1 / 100;
        pos = eLogService.initPos(pos, randomAccessFile);
        randomAccessFile.seek(pos);
        String line = "";
        while (line != null) {
            line = new String(line.getBytes("ISO-8859-1"), "utf-8");
            ELogEntity singleLocalELog = eLogService.parseSingleLocalELog(line);
            line = randomAccessFile.readLine();
            System.out.println(line);
            System.out.println(1.0 * randomAccessFile.getFilePointer() / randomAccessFile.length() + "%");
            if (singleLocalELog.getTypeStr().equals("null")) {
                continue;
            }
            System.out.println("成功====> ");

            
        }
    }
}
